package ar.edu.uba.fi.jmit.monitorengine.parser;

import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

import ar.edu.uba.fi.jmit.monitorengine.core.ConfigurationManager;
import ar.edu.uba.fi.jmit.monitorengine.parser.exceptions.XMLParserRuntimeException;

public class XMLVisualizerParser extends DefaultHandler {

	//Names of the tags
	private static final String VISUALIZER_TAG = "visualizer";
	private static final String NAME_VISUALIZER_TAG = "name";
	private static final String MONITORS_TAG = "monitors";
	private static final String NAME_MONITORS_TAG = "name";
	private static final String CONNECTION_TAG = "connection";
	private static final String PROTOCOL_CONNECTION_TAG = "protocol";
	private static final String IP_CONNECTION_TAG = "ip";
	private static final String PORT_CONNECTION_TAG = "port";
	private static final String CONTEXT_CONNECTION_TAG = "context";

	private boolean parseConnection = false;
	private String visualizerName;
	private List<String> monitorsParsed = null;
	private boolean areMonitorsParsed;
	
	private XMLVisualizerParser(List<String> monitorsParsed){
		this.monitorsParsed = monitorsParsed;
		this.areMonitorsParsed = false;
	}
	
	public static void parse(String pathToFile, List<String> monitorsParsed) throws SAXException, IOException{
		XMLReader xr = XMLReaderFactory.createXMLReader();
		XMLVisualizerParser handler = new XMLVisualizerParser(monitorsParsed);
		xr.setContentHandler(handler);
		xr.setErrorHandler(handler);
		FileReader r = new FileReader(pathToFile);
		xr.parse(new InputSource(r));
	}
	
	private void validateVisualizerParse(Attributes atts) {
		if (atts.getIndex(NAME_VISUALIZER_TAG) == -1){
			throw new XMLParserRuntimeException("Name tag of the visualizer is missing");
		}		
	}
	
	private void parseVisualizer(Attributes atts) {
		this.visualizerName = atts.getValue(NAME_VISUALIZER_TAG);
		this.parseConnection = true;
	}
	
	private void validateConnectionParse(Attributes atts){
		if (atts.getIndex(PROTOCOL_CONNECTION_TAG) == -1){
			throw new XMLParserRuntimeException("Protocol tag of the connection is missing");
		}
		if (atts.getIndex(IP_CONNECTION_TAG) == -1){
			throw new XMLParserRuntimeException("Ip tag of the connection is missing");
		}
		if (atts.getIndex(PORT_CONNECTION_TAG) == -1){
			throw new XMLParserRuntimeException("Port tag of the connection is missing");
		}
		if (atts.getIndex(CONTEXT_CONNECTION_TAG) == -1){
			throw new XMLParserRuntimeException("Context tag of the connection is missing");
		}
	}
	
	private void parseConnection(Attributes atts){
		Map<String,String> props = new HashMap<String, String>();
		
		props.put(PROTOCOL_CONNECTION_TAG, atts.getValue(PROTOCOL_CONNECTION_TAG));
		props.put(IP_CONNECTION_TAG, atts.getValue(IP_CONNECTION_TAG));
		props.put(PORT_CONNECTION_TAG, atts.getValue(PORT_CONNECTION_TAG));
		String context = atts.getValue(CONTEXT_CONNECTION_TAG);
		if(!context.startsWith("/")) {
			context = "/" + context;
		}
		props.put(CONTEXT_CONNECTION_TAG, context);
		
		ConfigurationManager.getInstance().addVisualizerProps(visualizerName, props);
		
		this.parseConnection = false;
	}
	

	private void validateMonitorsParse(Attributes atts) {
		if (atts.getIndex(NAME_MONITORS_TAG) == -1){
			throw new XMLParserRuntimeException("Name tag of the monitors is missing");
		}		
	}

	private void parseMonitors(Attributes atts) {
		ConfigurationManager.getInstance().addVisualizer(visualizerName, atts.getValue(NAME_MONITORS_TAG));
		areMonitorsParsed = true;
	}
	
	public void startElement(String uri, String name, String qName,	Attributes atts) {
		if (qName == VISUALIZER_TAG){
			this.validateVisualizerParse(atts);
			this.parseVisualizer(atts);
		}
		if (qName == MONITORS_TAG){
			this.validateMonitorsParse(atts);
			this.parseMonitors(atts);
		}
		if (this.parseConnection && qName == CONNECTION_TAG){
			this.validateConnectionParse(atts);
			this.parseConnection(atts);
		}
	}
	
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if (qName == VISUALIZER_TAG){
			if (areMonitorsParsed)
				areMonitorsParsed = false;
			else {
				for(String monitor : monitorsParsed)
					ConfigurationManager.getInstance().addVisualizer(visualizerName, monitor);
			}
		}
	}
}
